﻿import json
import urllib2
import urllib
import time
import codecs
import logging
from optparse import OptionParser
import versionInfo
from loadstone import db
from crc16 import crc16
from utils import * #locale tricks, gettext initialization ETC

class WikimapiaParser(object):
	WIKIMAPIA_KEY="B77710C2-983D0D71-E8927394-71C1594E-76E5A399-F0A8998A-FF415B45-D1A1A7DC"
	MAX_COUNT=100
	def __init__(self,email,lang="en"):
		self.user_id=crc16(email)
		self.id = int(time.time())-315360000
		self.db=db.DB()
		self.lang=lang
		self.log=logging.getLogger("WikimapiaConverter")

	def convertBoundingBox(self,minLon,minLat,maxLon,maxLat):
		url="http://api.wikimapia.org/?function=box&bbox={minLon},{minLat},{maxLon},{maxLat}&key={key}&page={page}&count={count}&language={lang}&format=json&disable=polygon"
		#determine number of results
		self.log.debug(_("Determining number of results"))
		response=urllib2.urlopen(url.format(minLat=minLat,minLon=minLon,maxLat=maxLat,maxLon=maxLon,key=self.WIKIMAPIA_KEY,lang=self.lang,count=1,page=1))
		results=json.load(response)["found"]
		self.log.debug(_("There are %d results for query")%results)
		#receive data
		pageCount=results/self.MAX_COUNT
		if results%self.MAX_COUNT>0:
			pageCount+=1
		for page in xrange(1,pageCount+1):	
			self.log.debug(_("Receiving page %d")%page)
			response=urllib2.urlopen(url.format(minLat=minLat,minLon=minLon,maxLat=maxLat,maxLon=maxLon,
			key=self.WIKIMAPIA_KEY,lang=self.lang,count=self.MAX_COUNT,page=page))
			self.jsonToLoadstoneDB(json.load(response))

	def jsonToLoadstoneDB(self,data):
		for obj in data["folder"]:
			self.addPOI(obj["name"],obj["location"]["lat"],obj["location"]["lon"])

	@staticmethod
	def filterName(name):
		return name.replace("&amp;quot;","'")

	def _filterData(self,data):
		"""removes nasty php warnings from input"""
		return data[data.index('{"'):]

	def searchPlace(self,text):
		"""Returns list of tuples (name,bboxString)"""
		url="http://api.wikimapia.org/?function=search&key={key}&page={page}&count={count}&language={lang}&format=json&disable=polygon&q={text}"
		text=urllib.quote_plus(text.encode('utf-8'))
		self.log.debug(_("Determining number of results"))
		response=urllib2.urlopen(url.format(text=text,key=self.WIKIMAPIA_KEY,lang=self.lang,count=1,page=1))
		data=json.loads(self._filterData(response.read()))
		if "debug" in data:
			raise RuntimeError(data["debug"][0]["message"])
		results=data["found"]
		self.log.debug(_("There are %d results for query")%results)
		pageCount=results/self.MAX_COUNT
		if results%self.MAX_COUNT>0:
			pageCount+=1
		result=[]
		for page in xrange(1,pageCount+1):
			self.log.debug(_("Receiving page %d")%page)
			response=urllib2.urlopen(url.format(text=text,key=self.WIKIMAPIA_KEY,lang=self.lang,count=self.MAX_COUNT,page=page))
			data=json.loads(self._filterData(response.read()))
			for obj in data["folder"]:
				c1=min(obj["location"]["east"],obj["location"]["west"])
				c2=min(obj["location"]["north"],obj["location"]["south"])
				c3=max(obj["location"]["east"],obj["location"]["west"])
				c4=max(obj["location"]["north"],obj["location"]["south"])
				result.append((self.filterName(obj["name"]),"%f,%f,%f,%f"%(c1,c2,c3,c4)))
		return result

	def addPOI(self,name,latitude,longitude):
		self.db.point.append(db.PointRecord(id=self.id,userid=self.user_id,
		name=self.filterName(name),latitude=int(latitude*db.mult),longitude=int(longitude*db.mult),accuracy=1,satellites=10,priority=0))
		self.id+=1

def init_logging():
	logging.getLogger().setLevel(logging.DEBUG)
	fileLog=logging.FileHandler("log.txt","w","utf-8")
	fileLog.setLevel(logging.DEBUG)
	fileLog.setFormatter(logging.Formatter('%(levelname)s %(name)s - %(asctime)s\n%(message)s'))
	logging.getLogger('').addHandler(fileLog)
	consoleLog=logging.StreamHandler()
	consoleLog.setLevel(logging.DEBUG)
	consoleLog.setFormatter(logging.Formatter('%(levelname)-8s: %(name)s -- %(message)s'))
	logging.getLogger('').addHandler(consoleLog)

opts = OptionParser(usage = _("""\
usage: %prog COMMAND=ARGUMENTS [options] LOADSTONEFILE
COMMAND can be one of the following:
bbox=lon_min,lat_min,lon_max,lat_max -- download and convert locations in given bounding box
search "string" -- prints names and bounding boxes of the results for the given search query"""),version=versionInfo.version,description=_("This tool receives data from wikimapia service and creates loadstone database from it. You need to have internet access for this tool to work."))
opts.add_option("-m","--e-mail",type="string",help=_("Your e-mail adress, must be the same as in your loadstone settings"))
opts.add_option("-l","--language",type="string",default="en",help=_("ISO 639-1 code of the language you want receive results in. Examples: 'en','ru','pl'"))
(options, args) = opts.parse_args()
if len(args) <2:
	opts.error(_("Not enough arguments given"))
initStdout()
init_logging()
if not options.e_mail:
	print _("Enter your e-mail adress:")
	options.e_mail=raw_input()
parser=WikimapiaParser(options.e_mail,options.language)
if args[0].startswith('bbox='):
	try:
		coords=args[0].split("=")[1].split(",")
		#convert to floats
		coords=[float(c) for c in coords]
	except IndexError,ValueError:
		opts.error(_("Invalid syntax for command 'bbox'"))
	parser.convertBoundingBox(*coords)
	with codecs.open(args[1],"w","utf-8") as f:
		parser.db.writeToBuffer(f)
elif args[0]=="search":
	t=args[1].replace('"','')
	#dirty algorithm to determine codepage
	try:
		text=t.decode('utf-8')
	except UnicodeDecodeError:
		try:
			text=t.decode('cp1251')
		except UnicodeDecodeError:
			raise RuntimeError(_("Can't recognize charset of input string"))
	result=parser.searchPlace(text)
	for r in result:
		print r[0]
		print r[1]
else: #unknown command
	opts.error(_("Unknown command '%s'")%args[0])
